File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
using UnityEngine.UI;
namespace BNG {
public class VRUISystem : BaseInputModule {
[Header("XR Controller Options : ")]
[Tooltip("This setting determines if LeftPointerTransform or RightPointerTransform will be used as a forward vector for World Space UI events")]
public ControllerHand SelectedHand = ControllerHand.Right;
#if XRIT_INTEGRATION
[Header("XR Interaction Toolkit Options : ")]
public bool UseXRInteractionToolkitUISystem = true;
#endif
[Tooltip("A transform on the left controller to use when raycasting for world space UI events")]
public Transform LeftPointerTransform;
[Tooltip("A transform on the right controller to use when raycasting for world space UI events")]
public Transform RightPointerTransform;
[Tooltip("Controller Binding to use for input down, up, etc.")]
public List<ControllerBinding> ControllerInput = new List<ControllerBinding>() { ControllerBinding.RightTrigger };
[Tooltip("Unity Input Action used to simulate a click or touch event")]
public InputActionReference UIInputAction;
[Tooltip("If true a PhysicsRaycaster component will be added to the UI camera, allowing physical objects to use IPointer events such as OnPointClick, OnPointEnter, etc.")]
public bool AddPhysicsRaycaster = false;
public LayerMask PhysicsRaycasterEventMask;
[Tooltip("If true the Right Thumbstick will send scroll events to the UI")]
public bool RightThumbstickScroll = true;
[Header("Shown for Debug : ")]
public GameObject PressingObject;
public GameObject DraggingObject;
public GameObject ReleasingObject;
public PointerEventData EventData { get; private set; }
Camera cameraCaster;
private GameObject _initialPressObject;
private bool _lastInputDown;
bool inputDown;
private static VRUISystem _instance;
public static VRUISystem Instance {
get {
if (_instance == null) {
_instance = GameObject.FindObjectOfType<VRUISystem>();
if (_instance == null) {
// Check for existing event system
EventSystem eventSystem = EventSystem.current;
if(eventSystem == null) {
eventSystem = new GameObject("EventSystem").AddComponent<EventSystem>(); ;
}
_instance = eventSystem.gameObject.AddComponent<VRUISystem>();
}
}
return _instance;
}
}
protected override void Awake() {
#if XRIT_INTEGRATION
if(!UseXRInteractionToolkitUISystem) {
initEventSystem();
}
#else
initEventSystem();
#endif
}
protected virtual void initEventSystem() {
UpdateControllerHand(SelectedHand);
AssignCameraToAllCanvases(cameraCaster);
EventData = new PointerEventData(eventSystem);
EventData.position = new Vector2(cameraCaster.pixelWidth / 2, cameraCaster.pixelHeight / 2);
}
protected override void Start() {
base.Start();
#if XRIT_INTEGRATION
if (UseXRInteractionToolkitUISystem) {
AssignCameraToAllCanvases(Camera.main);
if (this.gameObject.activeSelf) {
// Debug.Log("Diabling VRIF's VRUISystem since XR Interaction Kit UI support is enabled");
this.enabled = false;
}
}
#else
AssignCameraToAllCanvases(cameraCaster);
#endif
}
void init() {
if(cameraCaster == null) {
// Create the camera required for the caster.
// We can reduce the fov and disable the camera component for performance
var go = new GameObject("CameraCaster");
cameraCaster = go.AddComponent<Camera>();
cameraCaster.stereoTargetEye = StereoTargetEyeMask.None;
cameraCaster.fieldOfView = 5f;
cameraCaster.nearClipPlane = 0.01f;
cameraCaster.clearFlags = CameraClearFlags.Nothing;
cameraCaster.enabled = false;
// Add PhysicsRaycaster so other objects can subscribe to IPointer events
if(AddPhysicsRaycaster) {
var pr = go.AddComponent<PhysicsRaycaster>();
pr.eventMask = PhysicsRaycasterEventMask;
}
}
}
public override void Process() {
#if XRIT_INTEGRATION
// XRIT doesn't process here
if(UseXRInteractionToolkitUISystem == false) {
DoProcess();
}
#else
DoProcess();
#endif
}
public void DoProcess() {
// Input isn't ready if this Camera Caster's gameObject isn't active
if (EventData == null || !CameraCasterReady()) {
return;
}
EventData.position = new Vector2(cameraCaster.pixelWidth / 2, cameraCaster.pixelHeight / 2);
eventSystem.RaycastAll(EventData, m_RaycastResultCache);
EventData.pointerCurrentRaycast = FindFirstRaycast(m_RaycastResultCache);
m_RaycastResultCache.Clear();
// Handle Hover
HandlePointerExitAndEnter(EventData, EventData.pointerCurrentRaycast.gameObject);
// Handle Drag
ExecuteEvents.Execute(EventData.pointerDrag, EventData, ExecuteEvents.dragHandler);
// Handle scroll
if (RightThumbstickScroll) {
EventData.scrollDelta = InputBridge.Instance.RightThumbstickAxis;
if (!Mathf.Approximately(EventData.scrollDelta.sqrMagnitude, 0)) {
ExecuteEvents.Execute(ExecuteEvents.GetEventHandler<IScrollHandler>(EventData.pointerCurrentRaycast.gameObject), EventData, ExecuteEvents.scrollHandler);
}
}
// Press Events
inputDown = InputReady();
// On Trigger Down > TriggerDownValue this frame but not last
if (inputDown && _lastInputDown == false) {
PressDown();
}
// On Held Down
else if (inputDown) {
Press();
}
// On Release
else {
Release();
}
_lastInputDown = inputDown;
}
public virtual bool InputReady() {
// Input isn't ready if this Camera Caster's gameObject isn't active
if(!CameraCasterReady()) {
return false;
}
// Check Unity Action
if (UIInputAction != null && UIInputAction.action.ReadValue<float>() == 1f) {
return true;
}
// Check for bound controller button
for (int x = 0; x < ControllerInput.Count; x++) {
if (InputBridge.Instance.GetControllerBindingValue(ControllerInput[x])) {
return true;
}
}
return false;
}
/// <summary>
/// Returns true if we have a camera caster enabled and ready to send out data
/// Returns false if the camera caster is null or it's gameobject is disabled
/// </summary>
/// <returns></returns>
public virtual bool CameraCasterReady() {
if (cameraCaster != null && !cameraCaster.gameObject.activeInHierarchy) {
return false;
}
return true;
}
public virtual void PressDown() {
EventData.pointerPressRaycast = EventData.pointerCurrentRaycast;
// Deselect if selection changed
if(_initialPressObject != null) {
// ExecuteEvents.Execute(_initialPressObject, EventData, ExecuteEvents.deselectHandler);
_initialPressObject = null;
}
_initialPressObject = ExecuteEvents.GetEventHandler<IPointerClickHandler>(EventData.pointerPressRaycast.gameObject);
// Set Press Objects and Events
SetPressingObject(_initialPressObject);
ExecuteEvents.Execute(EventData.pointerPress, EventData, ExecuteEvents.pointerDownHandler);
// Set Drag Objects and Events
SetDraggingObject(ExecuteEvents.GetEventHandler<IDragHandler>(EventData.pointerPressRaycast.gameObject));
ExecuteEvents.Execute(EventData.pointerDrag, EventData, ExecuteEvents.beginDragHandler);
}
public virtual void Press() {
EventData.pointerPressRaycast = EventData.pointerCurrentRaycast;
// Set Press Objects and Events
SetPressingObject(ExecuteEvents.GetEventHandler<IPointerClickHandler>(EventData.pointerPressRaycast.gameObject));
ExecuteEvents.Execute(EventData.pointerPress, EventData, ExecuteEvents.pointerDownHandler);
// Set Drag Objects and Events
SetDraggingObject(ExecuteEvents.GetEventHandler<IDragHandler>(EventData.pointerPressRaycast.gameObject));
ExecuteEvents.Execute(EventData.pointerDrag, EventData, ExecuteEvents.beginDragHandler);
}
public virtual void Release() {
SetReleasingObject(ExecuteEvents.GetEventHandler<IPointerClickHandler>(EventData.pointerCurrentRaycast.gameObject));
// Considered a click event if released after an initial click
if (EventData.pointerPress == ReleasingObject) {
ExecuteEvents.Execute(EventData.pointerPress, EventData, ExecuteEvents.pointerClickHandler);
}
ExecuteEvents.Execute(EventData.pointerPress, EventData, ExecuteEvents.pointerUpHandler);
ExecuteEvents.Execute(EventData.pointerDrag, EventData, ExecuteEvents.endDragHandler);
// Send deselect to
// ExecuteEvents.Execute(ReleasingObject, EventData, ExecuteEvents.deselectHandler);
ClearAll();
}
public virtual void ClearAll() {
SetPressingObject(null);
SetDraggingObject(null);
EventData.pointerCurrentRaycast.Clear();
}
public virtual void SetPressingObject(GameObject pressing) {
EventData.pointerPress = pressing;
PressingObject = pressing;
}
public virtual void SetDraggingObject(GameObject dragging) {
EventData.pointerDrag = dragging;
DraggingObject = dragging;
}
public virtual void SetReleasingObject(GameObject releasing) {
ReleasingObject = releasing;
}
public virtual void AssignCameraToAllCanvases(Camera cam) {
Canvas[] allCanvas = FindObjectsOfType<Canvas>();
for (int x = 0; x < allCanvas.Length; x++) {
AddCanvasToCamera(allCanvas[x], cam);
}
}
public virtual void AddCanvas(Canvas canvas) {
#if XRIT_INTEGRATION
if(UseXRInteractionToolkitUISystem) {
AddCanvasToCamera(canvas, Camera.main);
// Add raycaster if not already present
canvas.gameObject.AddComponent<UnityEngine.XR.Interaction.Toolkit.UI.TrackedDeviceGraphicRaycaster>();
}
else {
AddCanvasToCamera(canvas, cameraCaster);
}
#else
AddCanvasToCamera(canvas, cameraCaster);
#endif
}
public virtual void AddCanvasToCamera(Canvas canvas, Camera cam) {
if(cam != null) {
canvas.worldCamera = cam;
}
}
public virtual void UpdateControllerHand(ControllerHand hand) {
// Make sure variables exist
init();
// Setup the Transform
if (hand == ControllerHand.Left && LeftPointerTransform != null) {
cameraCaster.transform.parent = LeftPointerTransform;
cameraCaster.transform.localPosition = Vector3.zero;
cameraCaster.transform.localEulerAngles = Vector3.zero;
}
else if (hand == ControllerHand.Right && RightPointerTransform != null) {
cameraCaster.transform.parent = RightPointerTransform;
cameraCaster.transform.localPosition = Vector3.zero;
cameraCaster.transform.localEulerAngles = Vector3.zero;
}
}
}
}